package zsd.reiview.experiment.crf;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


import com.aliasi.chunk.Chunking;
import com.aliasi.corpus.Corpus;
import com.aliasi.corpus.ListCorpus;
import com.aliasi.corpus.ObjectHandler;
import com.aliasi.corpus.XValidatingObjectCorpus;
import com.aliasi.util.AbstractExternalizable;

import zsd.reiview.experiment.crf.TrainCorpusFilter.FilterResultMatrix;
import zsd.reiview.experiment.crf.TrainCorpusFilter.Instance;
import zsd.reiview.experiment.crf.TrainCorpusFilter.InstanceCompair;
import Jama.Matrix;

/**
 * @Title: GraphRank.java
 * @Package zsd.reiview.experiment.crf
 * @Description: TODO(添加描述)
 * @author 朱圣代
 * @date 2011-11-4 上午09:55:32
 * @version V1.0
 */
public class GraphRank {

	/**
	 * @Title: main
	 * @Description:
	 * @param @param args
	 * @return void
	 * @throws
	 * @date 2011-11-4 上午09:55:32
	 */

	int dim;
	Matrix tranMatrix;
	double alph;
	double beita;
	Matrix initValue;
	double[] ranked;

	public GraphRank(int num, double alph, double beita, double[] initValue, double[][] tran) {
		this.dim = num;
		this.alph = alph;
		this.beita = beita;
		this.tranMatrix = new Matrix(tran);
		this.initValue = new Matrix(initValue, 1);
	}

	public GraphRank() {
	}

	public GraphRank(String path, double alph, double beita) throws Exception, Exception {
		FilterResultMatrix filterResultMatrix = (FilterResultMatrix) AbstractExternalizable.readObject(new File(path));

		this.dim = filterResultMatrix.dim;
		this.alph = alph;
		this.beita = beita;
		double[] init = new double[dim];
		double[][] trainMat = new double[dim][dim];
		for (int i = 0; i < dim; i++)
			init[i] = (double) filterResultMatrix.init[i];
		for (int i = 0; i < dim; i++)
			for (int j = 0; j < dim; j++)
				trainMat[i][j] = (double) filterResultMatrix.tran[i][j];
		this.tranMatrix = new Matrix(trainMat);
		this.initValue = new Matrix(init, 1);
	}

	public GraphRank(int num, double beita2, double gama, float[] initValue2, float[][] tran) {
		this.dim = num;
		this.alph = alph;
		this.beita = beita;
		double[] init = new double[dim];
		double[][] trainMat = new double[dim][dim];
		for (int i = 0; i < dim; i++)
			init[i] = (double) initValue2[i];
		for (int i = 0; i < dim; i++)
			for (int j = 0; j < dim; j++)
				trainMat[i][j] = (double) tran[i][j];
		this.tranMatrix = new Matrix(trainMat);
		this.initValue = new Matrix(init, 1);
	}

	public double[] rank() {
		normRow(initValue);
		normTran();

		Matrix mmMatrix = Matrix.identity(dim, dim);
		tranMatrix = tranMatrix.transpose();
		tranMatrix.timesEquals(beita);
		mmMatrix.minusEquals(tranMatrix);
		mmMatrix = mmMatrix.inverse();
		mmMatrix = mmMatrix.times(initValue.transpose());
		mmMatrix.timesEquals(1 - beita);
		ranked = mmMatrix.getColumnPackedCopy();
		return ranked;
	}

	public static void normRow(Matrix mat) {
		int row = mat.getRowDimension();
		int col = mat.getColumnDimension();
		double noZero = 1 / (double) col;
		for (int i = 0; i < row; i++) {
			int[] rowIndex = { i };
			Matrix rowMatrix = mat.getMatrix(rowIndex, 0, col - 1);
			double sum = rowMatrix.normInf();
			if (sum == 0) {
				rowMatrix = new Matrix(1, col - 1, noZero);
			} else {
				for (int j = 0; j < col; j++)
					rowMatrix.set(0, j, rowMatrix.get(0, j) / sum);
			}
			mat.setMatrix(rowIndex, 0, col - 1, rowMatrix);
		}
	}

	public void normTran() {
		normRow(tranMatrix);
		double noZero = 1 / (double) dim;
		Matrix matrix = new Matrix(dim, dim, noZero);
		matrix.timesEquals(1 - alph);
		tranMatrix.timesEquals(alph);
		tranMatrix.plusEquals(matrix);
	}

	int N;
	List<Chunking> chunkings;

	public int graph;
	public double alph2;
	public XValidatingObjectCorpus<Chunking> getRankedCorpus(int graph, String name, int type, int testNum, double alph, double beita, double gama, XValidatingObjectCorpus<Chunking> trainCorpus,
			XValidatingObjectCorpus<Chunking> test, int time, boolean update, int split) throws Exception {
		this.alph = beita;
		this.beita = gama;
		this.graph = graph;
		
		buildfromFilter(name, type, testNum, alph, trainCorpus, test, time, update, split);
		if (graph == 0) {
			ranked = initValue.getColumnPackedCopy();
		} else if( graph == 1 || graph == 4 || graph == 4){
			rank();
		}else if ( graph == 2 ) {
			ranked = new double[dim];
			Arrays.fill(ranked, 1.0);
		}else if ( graph == 3 ) {
			double [] initArray = new double[dim];
			Arrays.fill(initArray, 1.0);
			initValue = new Matrix(initArray, 1);
			rank();
		}
		List<Instance> instances = new ArrayList<Instance>();
		for (int i = 0; i < dim; i++) {
			Instance instance = new Instance();
			instance.setChunking(chunkings.get(i));
			instance.setSim(ranked[i]);
			instances.add(instance);
		}
		Collections.sort(instances, new InstanceCompair());

		XValidatingObjectCorpus<Chunking> corpus = new XValidatingObjectCorpus<Chunking>(trainCorpus.numFolds());

		for (int i = 0; i < dim && i < testNum; i++)
			corpus.handle(instances.get(i).getChunking());
		return corpus;
	}

	public void buildfromFilter(String name, int type, int testNum, double alph, XValidatingObjectCorpus<Chunking> trainCorpus, XValidatingObjectCorpus<Chunking> test, int time, boolean update,
			int split) throws Exception {
		this.N = testNum;
		TrainCorpusFilter trainCorpusFilter = new TrainCorpusFilter();
		trainCorpusFilter.FilterCorpus(name, type, testNum, alph, testNum, alph, trainCorpus, test, time, update, split);
		chunkings = trainCorpusFilter.getTrainChunkings();
		float[] initValue = trainCorpusFilter.initValue;
		float[][] tran = trainCorpusFilter.tran;
		this.dim = trainCorpusFilter.dim;
		double[] init = new double[dim];
		double[][] trainMat = new double[dim][dim];
		for (int i = 0; i < dim; i++)
			init[i] = (double) initValue[i];
		if ( graph == 1) {
			for (int i = 0; i < dim; i++)
				for (int j = 0; j < dim; j++)
					trainMat[i][j] = (double) tran[i][j];
		}else if ( graph == 4 ) {
			for (int i = 0; i < dim; i++)
				for (int j = 0; j < dim; j++)
					trainMat[i][j] = trainCorpusFilter.getTranTokMatrix()[i][j] * alph2 + ( 1- alph2 ) *  trainCorpusFilter.getTranFeatMatrix()[i][j];
		}
		this.tranMatrix = new Matrix(trainMat);
		this.initValue = new Matrix(init, 1);
	}

	/*
	 * Vector initVector; Vector rankedVector;
	 * 
	 * 
	 * public GraphRank(int num, double alph, double beita, double[] initValue,
	 * double[][] tran) { this.dim = dim; alph = alph; this.beita = beita;
	 * tranMatrix = new DenseMatrix(tran); initVector = new
	 * DenseVector(initVector); }
	 */

	/*
	 * public static DenseMatrix getIMatrix( int dim){ DenseMatrix I = new
	 * DenseMatrix(dim, dim); for(int i=0; i<dim; i++) I.setValue(i, i, 1.0);
	 * return I; }
	 * 
	 * public static Matrix inverseMatrix(Matrix m){ int row = m.numRows(); int
	 * col = m.numColumns(); Matrix mmMatrix = new DenseMatrix( col, row); for(int
	 * i=0 ; i< row; i++ ) for( int j=0; j< col; j++) mmMatrix.setValue(i, j,
	 * m.value(j, i)); return mmMatrix; }
	 */
	
	public ListCorpus<Chunking> getListRankedCorpus(int graph, String name, int type, int testNum, double alph, double beita, double gama,ListCorpus<Chunking> trainCorpus,
			ListCorpus<Chunking> test, int time, boolean update, int split) throws Exception {
		this.alph = beita;
		this.beita = gama;
		this.graph = graph;
		
		buildfromFilter(name, type, testNum, alph, trainCorpus, test, time, update, split);
		if (graph == 0) {
			ranked = initValue.getColumnPackedCopy();
		} else if( graph == 1 || graph == 4 || graph == 5){
			rank();
		}else if ( graph == 2 ) {
			ranked = new double[dim];
			Arrays.fill(ranked, 1.0);
		}else if ( graph == 3 ) {
			double [] initArray = new double[dim];
			Arrays.fill(initArray, 1.0);
			initValue = new Matrix(initArray, 1);
			rank();
		}
		List<Instance> instances = new ArrayList<Instance>();
		for (int i = 0; i < dim; i++) {
			Instance instance = new Instance();
			instance.setChunking(chunkings.get(i));
			instance.setSim(ranked[i]);
			instances.add(instance);
		}
		Collections.sort(instances, new InstanceCompair());

		ListCorpus<Chunking> corpus = new ListCorpus<Chunking>();

		for (int i = 0; i < dim && i < testNum; i++)
			corpus.addTrain(instances.get(i).getChunking());
		return corpus;
	}

	public void buildfromFilter(String name, int type, int testNum, double alph, ListCorpus<Chunking> trainCorpus,ListCorpus<Chunking> test, int time, boolean update,
			int split) throws Exception {
		this.N = testNum;
		TrainCorpusFilter trainCorpusFilter = new TrainCorpusFilter();
		trainCorpusFilter.FilterCorpus(name, type, testNum, alph, testNum, alph, trainCorpus, test, time, update, split);
		chunkings = trainCorpusFilter.getTrainChunkings();
		float[] initValue = trainCorpusFilter.initValue;
		float[][] tran = trainCorpusFilter.tran;
		this.dim = trainCorpusFilter.dim;
		double[] init = new double[dim];
		double[][] trainMat = new double[dim][dim];
		for (int i = 0; i < dim; i++)
			init[i] = (double) initValue[i];
		if ( graph == 1) {
			for (int i = 0; i < dim; i++)
				for (int j = 0; j < dim; j++)
					trainMat[i][j] = (double) tran[i][j];
		}else if ( graph == 4 ) {
			for (int i = 0; i < dim; i++)
				for (int j = 0; j < dim; j++)
					trainMat[i][j] = trainCorpusFilter.getTranTokMatrix()[i][j] * alph2 + ( 1- alph2 ) *  trainCorpusFilter.getTranFeatMatrix()[i][j];
		}
		this.tranMatrix = new Matrix(trainMat);
		this.initValue = new Matrix(init, 1);
	}

	public static void main(String[] args) throws Exception {
		GraphRank graphRank = new GraphRank("G:\\1.txt", 0.9, 0.9);
		graphRank.rank();
	}

}
